package com.outstanding.ifml.parser;

import static com.outstanding.ifml.parser.IFMLToken.BLANK;
import static com.outstanding.ifml.parser.IFMLToken.TABBLANK;
import static com.outstanding.ifml.parser.IFMLToken.COLON;
import static com.outstanding.ifml.parser.IFMLToken.COMMA;
import static com.outstanding.ifml.parser.IFMLToken.COMMENT;
import static com.outstanding.ifml.parser.IFMLToken.*;
import static com.outstanding.ifml.parser.IFMLToken.EOF;
import static com.outstanding.ifml.parser.IFMLToken.IDENTIFIER;
import static com.outstanding.ifml.parser.IFMLToken.LBRACKET;
import static com.outstanding.ifml.parser.IFMLToken.LITERALS;
import static com.outstanding.ifml.parser.IFMLToken.LPAREN;
import static com.outstanding.ifml.parser.IFMLToken.RBRACKET;
import static com.outstanding.ifml.parser.IFMLToken.RETURN;
import static com.outstanding.ifml.parser.IFMLToken.RPAREN;
import static com.outstanding.ifml.parser.IFMLToken.LBRACE;
import static com.outstanding.ifml.parser.IFMLToken.RBRACE;
import java.util.ArrayList;
import java.util.List;

import com.outstanding.ifml.exception.IFMLException;
import com.outstanding.ifml.Code;
import com.outstanding.ifml.IFML;
import com.outstanding.ifml.IFMLPaserProperties;

import com.outstanding.ifml.Item;
import com.outstanding.ifml.ItemProperty;
import com.outstanding.ifml.ItemValueClass;
import com.outstanding.ifml.Parser;
import com.outstanding.ifml.warpper.ArrayValue;
import com.outstanding.ifml.warpper.Comment;
import com.outstanding.ifml.warpper.EndToken;
import com.outstanding.ifml.warpper.Identifier;
import com.outstanding.ifml.warpper.Liner;
import com.outstanding.ifml.warpper.Prop;
import com.outstanding.ifml.warpper.StartToken;
import com.outstanding.ifml.warpper.State;
import com.outstanding.ifml.warpper.Token;
import com.outstanding.ifml.warpper.TokenType;
import com.outstanding.ifml.warpper.Value;
import com.outstanding.ifml.warpper.ValueType;

/**
 * 解析器
 * 
 * @author chenzhixuan
 *
 */
public class DefaultParser implements Parser {

	protected IFMLLexer lexer;

	public List<Liner> getCommentLiners() {
		return commentLiners;
	}

	protected final List<Liner> commentLiners = new ArrayList<Liner>();

	public DefaultParser() {
	}

	private IFMLPaserProperties properties;

	@Override
	public void init(IFMLLexer lexer) {
		this.lexer = lexer;
		this.properties = lexer.getProperties();
	}

	// 解析的根
	private Liner Root = new Liner(-1);;

	private Liner currentLiner;

	// 处理行间逻辑
	private void putLiner(Liner liner) {
		// 判断是否为有效行
		if (liner.isValid()) {
			if (liner.getSpNum() == 0) {
				this.Root.addSubliner(liner);
				liner.setFarther(Root);
				this.currentLiner = liner;
				return;
			} else if (this.currentLiner == null) {
				throw new IFMLException(Code.P1001, "接口定义的第一行必须零空格开始");
			} else {
				// 找到该行的父级行
				findFarther(this.currentLiner, liner);
				this.currentLiner = liner;
			}

		} else {
			commentLiners.add(liner);
		}
	}

	// 通过行间进行上下文判断父子关系
	private static void findFarther(Liner current, Liner liner) {
		// 兄弟行
		if (liner.getSpNum() == current.getSpNum()) {
			current.getFarther().addSubliner(liner);
			liner.setFarther(current.getFarther());
			return;
		}
		// 子行
		else if (liner.getSpNum() > current.getSpNum()) {
			List<Liner> subliners = current.getSubliner();
			if (subliners != null && subliners.size() > 0) {
				Liner bf = subliners.get(0);
				if (bf.getSpNum() != liner.getSpNum()) {
					throw new IFMLException(Code.P1002, liner.getContent() + "," + bf.getContent()
							+ "父行中的子行的空格数不相同,待加入的行的空格数=" + liner.getSpNum() + ",原子行的行数为" + bf.getSpNum());
				}
			}
			liner.setFarther(current);
			current.addSubliner(liner);
			return;

		}
		// 往上推级
		else {
			Liner fa = current.getFarther();
			findFarther(fa, liner);
			return;
		}
	}

	// : 以后的
	/**
	 * 
	 * @param next
	 *            :以后的字符ascii码
	 * @return
	 */
	private Token afterCOLON(int next, char nextChar, Token t, Liner liner) {
		final IFMLLexer lexer = getLexer();
		String str = null;
		switch (next) {
		case LBRACKET:
			Value arrayV = new ArrayValue();
			String[] arrayStr = lexer.arrayStringVal();
			for (String as : arrayStr)
				arrayV.setLiteral(as);
			return arrayV;
		case COMMENT:
			Comment comment = new Comment();
			str = lexer.commentVal();
			comment.setLiteral(str);
			return comment;
		case DOUBLEQUOTATION:
			Value v = new Value();
			str = lexer.doubleQuotationStringVal();
			v.setLiteral(str);
			return v;
		case SINGLEQUOTATION:
			Value vv = new Value();
			str = lexer.singleQuotationStringVal();
			vv.setLiteral(str);
			return vv;
		case RETURN:
			t.complete();
			return new EndToken();
		case EOF:
			t.complete();
			return new EndToken();
		default:
			throw new IFMLException(Code.P1003, liner.getNum() + "行 has an Exception,该字符非法" + nextChar);
		}

	}

	/**
	 * 按一行行开始解析
	 * 
	 * @param liner
	 *            行对象
	 * @param num
	 *            行数
	 */
	// 开始按行来解析
	public void parseLiner(Liner liner, int num) {
		final IFMLLexer lexer = getLexer();
		// 如果行对象是空，则意味着是一个新行。
		if (liner == null) {
			liner = new Liner(++num);
			lexer.setCurLiner(liner);
		}

		// 开始获取当前字符
		char c = lexer.getChar();
		Token t = liner.getCurrentToken();
		label: switch (lexer.token()) {
		// tab空格
		case TABBLANK:
			for (int i = 0; i < lexer.getProperties().getTab_size(); i++) {
				// 记录行首空格，是否为行首，由liner控制
				liner.countFirstBlank();
			}
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		case BLANK:
			// 行首空格
			liner.countFirstBlank();
			lexer.nextToken();
			parseLiner(liner, num);
			break;

		case RETURN:
			t.complete();
			// 行结束处理
			liner.setCurrentToken(new EndToken());
			putLiner(liner);
			lexer.nextToken();
			// 新的行
			num++;
			parseLiner(null, num);
			break;
		case EOF: // 文件的结束符

			t.complete();
			liner.setCurrentToken(new EndToken());
			putLiner(liner);
			break;
		case IDENTIFIER:
			String str = lexer.identifierVal(c);
			if (t.getType() == TokenType.START) {
				Identifier id = new Identifier();
				id.setLiteral(str);
				liner.setCurrentToken(id);
				t = id;
			}
			// (name
			else if (t.getType() == TokenType.PROP && t.getState() == State.init) {
				Prop p = (Prop) t;
				Identifier id = new Identifier();
				id.setLiteral(str);
				p.setIdentifier(id);
			} // (named:valued,named
			else if (t.getType() == TokenType.PROP && t.getState() == State.finish) {
				Prop p = new Prop();
				Identifier id = new Identifier();
				id.setLiteral(str);
				p.setIdentifier(id);
				liner.setCurrentToken(p);
				t = p;
			} else {
				throw new IFMLException(Code.P1004, liner.getContent() + "行的下一个词元不正确: " + t.toString());
			}
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		/**
		 * 当为：时，可能有两种情况，一个是属性设定，一个是本身值的设定。如何判断
		 */
		case COLON: // 取后面的值有两种情况（空已经不可能），一个是直接返回字母和数字组合的，当遇见[ ]时，则直接返回""
			// ( named :value
			lexer.readNextToken();
			int next = lexer.token();
			char nextChar = lexer.getChar();
			if (t.getType() == TokenType.PROP && t.getState() == State.naming
					|| (t.getType() == TokenType.PROP && t.getState() == State.init)) {
				Prop p = (Prop) t;
				Token nexttoken = afterCOLON(next, nextChar, t, liner);
				if (!(nexttoken instanceof Value)) {
					throw new IFMLException(Code.P1005, "第" + liner.getNum() + "行的下一个词元类型不正确: char=" + nextChar);
				} else {
					Value value = (Value) nexttoken;
					p.onPutColon(value);
				}
			}
			// (named:valued):value
			// named : value
			else if ((t.getType() == TokenType.IDENTIFIER)
					|| (t.getType() == TokenType.PROP && t.getState() == State.finish)) {
				Token nexttoken = afterCOLON(next, nextChar, t, liner);
				if (nexttoken instanceof EndToken) {
					EndToken end = (EndToken) nexttoken;
					liner.setCurrentToken(end);
					lexer.nextToken();
					num++;
					putLiner(liner);
					parseLiner(null, num);
					break;
				} // 直接结束了
				else if (nexttoken instanceof Comment) {
					t.complete();
					Comment comment = (Comment) nexttoken;
					liner.setCurrentToken(comment);

				} else {
					t.complete();
					Value value = (Value) nexttoken;
					liner.setCurrentToken(value);
				}
			} else {
				throw new IFMLException(Code.P1006, liner.getContent() + "行的下一个词元不正确: '" + nextChar + "'" + t.toString());

			}
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		case COMMENT:
			String strComment = lexer.commentVal();
			Comment comment = new Comment();
			comment.setLiteral(strComment);
			comment.complete();
			liner.setCurrentToken(comment);
			putLiner(liner);
			// 开始下一行
			lexer.nextToken();
			num++;
			parseLiner(null, num);
			break;
		// 一种情况，直接就是属性
		case DOUBLEQUOTATION:
			if (t.getType() == TokenType.PROP && t.getState() == State.init) {
				Prop p = (Prop) t;
				Value v = new Value();
				String strValue = lexer.doubleQuotationStringVal();
				v.setLiteral(strValue);
				p.setValue(v);
			} else {
				throw new IFMLException(Code.P1007, "第" + liner.getNum() + "行的下一个词元不正确: " + t.toString());
			}
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		case SINGLEQUOTATION:
			if (t.getType() == TokenType.PROP && t.getState() == State.init) {
				Prop p = (Prop) t;
				Value v = new Value();
				String strValue = lexer.singleQuotationStringVal();
				v.setLiteral(strValue);
				p.setValue(v);
			} else {
				throw new IFMLException(Code.P1008, "第" + liner.getNum() + "行的下一个词元不正确: " + t.toString());
			}
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		case COMMA: // , 一般都是在属性分割。 对于值因为都是在[]处理了
			if (t.getType() == TokenType.PROP) {
				t.complete();
				t = new Prop();
				liner.setCurrentToken(t);
			} else {
				throw new IFMLException(Code.P1009, "第" + liner.getNum() + "行的下一个词元不正确: " + t.toString());
			}
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		case LPAREN: // "("
			t.complete();
			Prop p = new Prop();
			liner.setCurrentToken(p);
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		case RPAREN: // ")"
			t.complete();
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		case LBRACE: // "{"
			Identifier id = new Identifier();
			String strLbrace = lexer.LbraceStringVal();
			id.setLiteral(strLbrace);
			liner.setCurrentToken(id);
			t = id;
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		case RBRACE:
			t.complete();
			lexer.nextToken();
			parseLiner(liner, num);
			break;
		default:
			throw new IFMLException(Code.P1010,
					"第" + liner.getNum() + "行 has an Exception,不支持该字符[" + lexer.getChar() + "]");

		}

	}

	private IFMLLexer getLexer() {
		return this.lexer;
	}

	private static Prop getTypeProp(List<Prop> props) {
		if (props == null)
			return null;
		for (Prop p : props) {
			//处理值属性
			if ("type".equals(p.getIdentifier().getLiteral())) {
				props.remove(p);
				return p;
			}

		}
		return null;
	}

	/**
	 * 程序的入口
	 */
	@Override
	public IFML parseIFML() {
		// 逐行解析
		this.parseLiner(null, 0);

		IFML ifml = new IFML();
		// 得到根行下的顶级行
		List<Liner> liners = Root.getSubliner();
		for (int i = 0; i < liners.size(); i++) {
			Item subIF = paddingItem(new Item(0), liners.get(i));
			// 将顶级元素加入到ifml对象中。
			ifml.addIF(subIF);
		}

		ifml.sort();
		return ifml;
	}

	/**
	 * 将行的词元装填到Item对象中
	 * 
	 * @param item
	 *            待装填的item对象
	 * @param liner
	 *            行对象
	 * @return
	 */
	public Item paddingItem(Item item, Liner liner) {
		if (!liner.isValid()) {
			throw new IFMLException(Code.P1011, "行解析错误，当前行" + liner.getNum() + "不是一个有效行");

		}
		item.setName(liner.getIdentifier().getLiteral());
		// 获取属性中的值type属性。
		List<Prop> props = liner.getProps();
		Prop p = getTypeProp(props);
		if (p != null && p.getValue() != null) {
			String value = p.getValue().getLiteral();
			if ("number".equals(value)) {
				item.setItemClass(ItemValueClass.number);
			} else if ("array".equals(value)) {
				item.setItemClass(ItemValueClass.array);
			} else if ("string".equals(value)) {
				item.setItemClass(ItemValueClass.string);
			} else if ("object".equals(value)) {
				item.setItemClass(ItemValueClass.object);
			} else if ("listobject".equals(value)) {
				item.setItemClass(ItemValueClass.listobject);
			} else {
				item.setItemClass(value);
			}
		} else {
			item.setItemClass(ItemValueClass.string);
		}

		// 装填属性
		
		if (props != null) {
			for (Prop prop : props) {
				ItemProperty itp = new ItemProperty();
				if (prop.getIdentifier() != null && prop.getIdentifier().getLiteral() != null) {
					itp.setName(prop.getIdentifier().getLiteral());
					itp.setValue(prop.getValue().getLiteral());
				} else {
					itp.setName(this.properties.getOnlyOneProperyName());
					itp.setValue(prop.getValue().getLiteral());
				}
				item.addProperty(itp);
			}
		}
		// 装填值
		if (liner.getValue() != null) {
			// 是否要
			Value val = liner.getValue();
			if (val instanceof ArrayValue) {
				item.setValue(((ArrayValue) val).getValues());
			} else {
				item.setValue(liner.getValue().getLiteral());
			}

		}

		// 处理子元素
		List<Liner> subliner = liner.getSubliner();

		for (Liner li : subliner) {
			Item subIF = paddingItem(new Item(item.getLevel() + 1), li);
			item.addChildIf(subIF);
		}

		return item;
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		List<Liner> liners = Root.getSubliner();
		for (Liner l : liners) {
			sb.append(l.toString());
			sb.append('\n');
		}
		for (Liner l : commentLiners) {
			sb.append(l.toString());
			sb.append('\n');
		}
		return sb.toString();
	}

}
